package net.hn.hnms.biz.training.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.net.MediaType;
import net.hn.hnms.biz.training.domain.PersonnelCertificate;
import net.hn.hnms.biz.training.mapper.PersonnelCertificateMapper;
import net.hn.hnms.biz.training.request.PersonnelCertificateReq;
import net.hn.hnms.biz.training.service.PersonnelCertificateService;
import net.hn.hnms.biz.training.vo.PersonCountVO;
import net.hn.hnms.biz.training.vo.PersonnelCertificateVo;
import net.hn.hnms.sys.common.core.constant.Constants;
import net.hn.hnms.sys.common.core.domain.ResponsePage;
import net.hn.hnms.sys.common.core.exception.HuaNengException;
import net.hn.hnms.sys.common.excel.core.ExcelResult;
import net.hn.hnms.sys.common.excel.utils.ExcelUtil;
import net.hn.hnms.sys.common.mybatis.core.page.PageQuery;
import net.hn.hnms.sys.common.redis.utils.RedisUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class PersonnelCertificateServiceImpl extends ServiceImpl<PersonnelCertificateMapper, PersonnelCertificate> implements PersonnelCertificateService {

    private final static String cacheKey = "personnel-result-dict";


    @Autowired
    private PersonnelCertificateMapper personnelCertificateMapper;

    @Override
    public void importOtherResult(MultipartFile file) {
        String sufix = StrUtil.subAfter(file.getOriginalFilename(), ".", true);
        if (!"xls".equals(sufix) && !"xlsx".equals(sufix))
            throw new HuaNengException(Constants.FAIL, "文件格式仅支持xls或xlsx");

        try {
            ExcelResult<PersonnelCertificate> excel = ExcelUtil.importExcel(file.getInputStream(), PersonnelCertificate.class, 2);
            List<PersonnelCertificate> entitiesFromExcel = excel.getList();
            if (CollUtil.isEmpty(entitiesFromExcel)) {
                if (CollUtil.isEmpty(excel.getErrorList())) {
                    throw new HuaNengException(Constants.FAIL, "文件未包含有效数据");
                }
                throw new HuaNengException(Constants.FAIL, excel.getErrorList().get(0));
            }
            entitiesFromExcel.stream().distinct().forEach(item -> item.setCreateTime(new Date()));
            entitiesFromExcel.stream().distinct().forEach(item -> item.setType("4"));

            int batchSize = 1000;
            int count = (int) Math.ceil(entitiesFromExcel.size() / (double) batchSize);
            for (int i = 0; i < count; i++) {
                personnelCertificateMapper.insertOrUpdateBatch(CollUtil.sub(entitiesFromExcel, i * batchSize, (i + 1) * batchSize));
            }
            RedisUtils.deleteObject(cacheKey);
        } catch (IOException e) {
            throw new HuaNengException(Constants.FAIL, "读取文件异常");
        }
    }

    @Override
    public void importSpecialOperationsResult(MultipartFile file) {
        String sufix = StrUtil.subAfter(file.getOriginalFilename(), ".", true);
        if (!"xls".equals(sufix) && !"xlsx".equals(sufix))
            throw new HuaNengException(Constants.FAIL, "文件格式仅支持xls或xlsx");

        try {
            ExcelResult<PersonnelCertificate> excel = ExcelUtil.importExcel(file.getInputStream(), PersonnelCertificate.class, 2);
            List<PersonnelCertificate> entitiesFromExcel = excel.getList();
            if (CollUtil.isEmpty(entitiesFromExcel)) {
                if (CollUtil.isEmpty(excel.getErrorList())) {
                    throw new HuaNengException(Constants.FAIL, "文件未包含有效数据");
                }
                throw new HuaNengException(Constants.FAIL, excel.getErrorList().get(0));
            }
            entitiesFromExcel.stream().distinct().forEach(item -> item.setCreateTime(new Date()));
            entitiesFromExcel.stream().distinct().forEach(item -> item.setType("3"));

            int batchSize = 1000;
            int count = (int) Math.ceil(entitiesFromExcel.size() / (double) batchSize);
            for (int i = 0; i < count; i++) {
                personnelCertificateMapper.insertBatch(CollUtil.sub(entitiesFromExcel, i * batchSize, (i + 1) * batchSize));
            }
            RedisUtils.deleteObject(cacheKey);
        } catch (IOException e) {
            throw new HuaNengException(Constants.FAIL, "读取文件异常");
        }
    }

    /**
     * 安全生产管理人员持证明细 模板下载
     *
     * @param response
     */
    @Override
    public void downloadpordManageUser(HttpServletResponse response) {
        OutputStream fos = null;
        ExcelWriter writer = null;
        try {
            fos = response.getOutputStream();
            writer = cn.hutool.poi.excel.ExcelUtil.getWriter(true);

            //持证人	员工编号	职务	任职时间	参加工作时间	学历	所学专业	人员类别	证件编号	发证日期	到期日期	是否在其他单位兼职	职称	职称专业	证件状态
            List<String> header = CollUtil.newArrayList("持证人", "员工编号", "岗位职务", "任职时间", "参加工作时间", "学历", "所学专业", "证件编号", "所在单位", "发证日期", "到期日期", "是否专业技术人员", "证件状态");
            List<List<String>> rows = new ArrayList<>();
            rows.add(header);
            writer.merge(12, "安全生产管理人员持证明细导入");
            writer.write(rows, true);

            response.reset();
            response.setContentType(MediaType.OCTET_STREAM.toString());
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("安全生产管理人员持证明细-模板.xlsx", "UTF-8"));
            writer.flush(fos, true);
        } catch (IOException e) {
            throw new HuaNengException(Constants.FAIL, "模板下载失败");
        } finally {
            IoUtil.close(fos);
            if (writer != null) writer.close();
        }
    }


    /**
     * 五职矿长与副总工程师持证明细
     *
     * @param response
     */
    @Override
    public void downloadbarmasterUser(HttpServletResponse response) {
        OutputStream fos = null;
        ExcelWriter writer = null;
        try {
            fos = response.getOutputStream();
            writer = cn.hutool.poi.excel.ExcelUtil.getWriter(true);

            //持证人	员工编号	职务	任职时间	参加工作时间	学历	所学专业	                                                                人员类别	证件编号	发证日期	到期日期	是否在其他单位兼职	职称	职称专业	证件状态
            List<String> header = CollUtil.newArrayList("持证人", "员工编号", "职务", "任职时间", "参加工作时间", "学历", "所学专业", "人员类别", "证件编号", "发证日期", "到期日期", "是否在其他单位兼职", "职称", "职称专业", "证件状态");
            List<List<String>> rows = new ArrayList<>();
            rows.add(header);
            writer.merge(14, "五职矿长与副总工程师持证明细导入");
            writer.write(rows, true);

            response.reset();
            response.setContentType(MediaType.OCTET_STREAM.toString());
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("五职矿长与副总工程师持证明细-模板.xlsx", "UTF-8"));
            writer.flush(fos, true);
        } catch (IOException e) {
            throw new HuaNengException(Constants.FAIL, "模板下载失败");
        } finally {
            IoUtil.close(fos);
            if (writer != null) writer.close();
        }
    }

    @Override
    public void downloadTrinidadAndTobago(HttpServletResponse response) {
        OutputStream fos = null;
        ExcelWriter writer = null;
        try {
            fos = response.getOutputStream();
            writer = cn.hutool.poi.excel.ExcelUtil.getWriter(true);

            //证件号码	员工编号	姓名	作业类别	准操项目	所在单位	发证日期	到期日期	证件状态
            List<String> header = CollUtil.newArrayList("证件编号", "员工编号", "姓名", "作业类别", "准操项目", "所在单位", "发证日期", "到期日期", "证件状态");
            List<List<String>> rows = new ArrayList<>();
            rows.add(header);
            writer.merge(8, "特种作业持证明细导入");
            writer.write(rows, true);

            response.reset();
            response.setContentType(MediaType.OCTET_STREAM.toString());
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("特种作业持证明细导入-模板.xlsx", "UTF-8"));
            writer.flush(fos, true);
        } catch (IOException e) {
            throw new HuaNengException(Constants.FAIL, "模板下载失败");
        } finally {
            IoUtil.close(fos);
            if (writer != null) writer.close();
        }
    }

    @Override
    public void downloadotherStaffsUser(HttpServletResponse response) {
        OutputStream fos = null;
        ExcelWriter writer = null;
        try {
            fos = response.getOutputStream();
            writer = cn.hutool.poi.excel.ExcelUtil.getWriter(true);

            //证件编号	员工编号	持证人	性别	作业类别	岗位职务	所在单位	发证日期	到期日期	证件状态	备注                                                                人员类别	证件编号	发证日期	到期日期	是否在其他单位兼职	职称	职称专业	证件状态
            List<String> header = CollUtil.newArrayList("证件编号", "员工编号", "持证人", "性别", "作业类别", "岗位职务", "所在单位", "发证日期", "到期日期", "证件状态", "备注");
            List<List<String>> rows = new ArrayList<>();
            rows.add(header);
            writer.merge(10, "煤矿其他从业人员导入");
            writer.write(rows, true);

            response.reset();
            response.setContentType(MediaType.OCTET_STREAM.toString());
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("煤矿其他从业人员-模板.xlsx", "UTF-8"));
            writer.flush(fos, true);
        } catch (IOException e) {
            throw new HuaNengException(Constants.FAIL, "模板下载失败");
        } finally {
            IoUtil.close(fos);
            if (writer != null) writer.close();
        }
    }

    /**
     * @return 无
     * @Description 导入
     * @Date 14:24 2022/8/24
     * @Param date 考评时间; file导入的excel文件
     **/
    @Override
    public void importResult(MultipartFile file, String type) {
        String sufix = StrUtil.subAfter(file.getOriginalFilename(), ".", true);
        if (!"xls".equals(sufix) && !"xlsx".equals(sufix))
            throw new HuaNengException(Constants.FAIL, "文件格式仅支持xls或xlsx");

        try {
            ExcelResult<PersonnelCertificate> excel = ExcelUtil.importExcel(file.getInputStream(), PersonnelCertificate.class, 2);
            List<PersonnelCertificate> entitiesFromExcel = excel.getList();
            if (CollUtil.isEmpty(entitiesFromExcel)) {
                if (CollUtil.isEmpty(excel.getErrorList())) {
                    throw new HuaNengException(Constants.FAIL, "文件未包含有效数据");
                }
                throw new HuaNengException(Constants.FAIL, excel.getErrorList().get(0));
            }
            Date date = new Date();
            entitiesFromExcel.stream().distinct().forEach(item -> {
                item.setCreateTime(date);
                item.setType(type);
            });

            /*int batchSize = 1000;
            int count = (int) Math.ceil(entitiesFromExcel.size() / (double) batchSize);
            for (int i = 0; i < count; i++) {
                this.saveOrUpdateBatch(CollUtil.sub(entitiesFromExcel, i * batchSize, (i + 1) * batchSize));
            }*/
            if ("1".equals(type)) {
                for (PersonnelCertificate personnelCertificate : entitiesFromExcel) {
                    LambdaUpdateWrapper<PersonnelCertificate> personnelCertificateUpdateWrapper = new LambdaUpdateWrapper<>();
                    personnelCertificateUpdateWrapper.eq(PersonnelCertificate::getEmployeeId, personnelCertificate.getEmployeeId());
                    personnelCertificateUpdateWrapper.eq(PersonnelCertificate::getType, personnelCertificate.getType());
                    this.saveOrUpdate(personnelCertificate, personnelCertificateUpdateWrapper);
                }
            }
            if ("2".equals(type)) {
                for (PersonnelCertificate personnelCertificate : entitiesFromExcel) {
                    LambdaUpdateWrapper<PersonnelCertificate> personnelCertificateUpdateWrapper = new LambdaUpdateWrapper<>();
                    personnelCertificateUpdateWrapper.eq(PersonnelCertificate::getEmployeeId, personnelCertificate.getEmployeeId());
                    personnelCertificateUpdateWrapper.eq(PersonnelCertificate::getType, personnelCertificate.getType());
                    this.saveOrUpdate(personnelCertificate, personnelCertificateUpdateWrapper);
                }
            }
            if ("3".equals(type)) {
                for (PersonnelCertificate personnelCertificate : entitiesFromExcel) {
                    LambdaUpdateWrapper<PersonnelCertificate> personnelCertificateUpdateWrapper = new LambdaUpdateWrapper<>();
                    personnelCertificateUpdateWrapper.eq(PersonnelCertificate::getEmployeeId, personnelCertificate.getEmployeeId());
                    personnelCertificateUpdateWrapper.eq(PersonnelCertificate::getType, personnelCertificate.getType());
                    this.saveOrUpdate(personnelCertificate, personnelCertificateUpdateWrapper);
                }
            }
            if ("4".equals(type)) {
                //作业类别 岗位职务 员工编号
                for (PersonnelCertificate personnelCertificate : entitiesFromExcel) {
                    LambdaUpdateWrapper<PersonnelCertificate> personnelCertificateUpdateWrapper = new LambdaUpdateWrapper<>();
                    personnelCertificateUpdateWrapper.eq(PersonnelCertificate::getEmployeeId, personnelCertificate.getEmployeeId());
                    personnelCertificateUpdateWrapper.eq(PersonnelCertificate::getType, personnelCertificate.getType());
                    personnelCertificateUpdateWrapper.eq(PersonnelCertificate::getPostPosition, personnelCertificate.getPostPosition() == null ? "--" : personnelCertificate.getPostPosition());
//                    personnelCertificateUpdateWrapper.eq(PersonnelCertificate::getOperationCategory,personnelCertificate.getOperationCategory());
                    this.saveOrUpdate(personnelCertificate, personnelCertificateUpdateWrapper);
                }
            }
            RedisUtils.deleteObject(cacheKey);
        } catch (IOException e) {
            throw new HuaNengException(Constants.FAIL, "读取文件异常");
        }
    }

    /**
     * 统计
     *
     * @return
     */
    @Override
    public List<PersonCountVO> PersonCount() {
        ArrayList<PersonCountVO> personCountVOS = new ArrayList<>();
        PersonCountVO personCountVO = null;
        for (int i = 0; i < 4; i++) {
            personCountVO = new PersonCountVO();
            personCountVO.setCertificateCount(calculateCount((i + 1) + "", "正常") + "");
            personCountVO.setEarlyWarningCount(calculateCount((i + 1) + "", "预警") + "");
            personCountVO.setNoCertificateCount(calculateCount((i + 1) + "", "无证") + "");
            personCountVO.setType((i + 1) + "");
            personCountVOS.add(personCountVO);
        }
        personCountVO = new PersonCountVO();
        personCountVO.setType("5");
        personCountVO.setCertificateCount(calculateCount("", "正常") + "");
        personCountVO.setEarlyWarningCount(calculateCount("", "预警") + "");
        personCountVO.setNoCertificateCount(calculateCount("", "无证") + "");
        personCountVOS.add(personCountVO);
        return personCountVOS;
    }

    @Override
    public void downloadCount(HttpServletResponse response) {
        OutputStream fos = null;
        ExcelWriter writer = null;
        try {
            fos = response.getOutputStream();
            writer = cn.hutool.poi.excel.ExcelUtil.getWriter(true);

            List<String> header = CollUtil.newArrayList("工种", "持证人数", "证件预警人数", "无证人数");

            List<List<String>> rows = new ArrayList<>();
            List<PersonCountVO> personCountVOS = PersonCount();
            rows.add(header);
            for (PersonCountVO vo : personCountVOS) {
                rows.add(CollUtil.newArrayList(vo.getType(), vo.getCertificateCount(), vo.getEarlyWarningCount(), vo.getNoCertificateCount()));
            }
            writer.merge(3, "持证情况导出");
            writer.write(rows);

            response.reset();
            response.setContentType(MediaType.OCTET_STREAM.toString());
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("持证情况导出.xlsx", "UTF-8"));
            writer.flush(fos, true);
        } catch (IOException e) {
            throw new HuaNengException(Constants.FAIL, "持证情况导出失败");
        } finally {
            IoUtil.close(fos);
            if (writer != null) writer.close();
        }
    }

    private long calculateCount(String type, String status) {
        LambdaUpdateWrapper<PersonnelCertificate> wrapper1 = new LambdaUpdateWrapper<>();
        if (type == null || "".equals(type)) {
            wrapper1.eq(PersonnelCertificate::getCertificateStatus, status);
        }
        if (type != null && !"".equals(type)) {
            wrapper1.eq(PersonnelCertificate::getType, type).eq(PersonnelCertificate::getCertificateStatus, status);
        }
        return this.count(wrapper1);
    }


    /**
     * @param planSale
     * @param pageQuery 查询回采计划列表
     */
    @Override
    public ResponsePage<PersonnelCertificateVo> selectPageList(PersonnelCertificateReq planSale, PageQuery pageQuery) {

        Page<PersonnelCertificate> page = personnelCertificateMapper.selectPage(pageQuery.build(), buildQuery(planSale).orderByDesc(PersonnelCertificate::getCreateTime));
        List<PersonnelCertificateVo> list = page.getRecords().stream().map(p -> {
            PersonnelCertificateVo personnelCertificateVo = new PersonnelCertificateVo();
            BeanUtils.copyProperties(p, personnelCertificateVo);
            return personnelCertificateVo;
        }).collect(Collectors.toList());
        return new ResponsePage<>(list, page.getTotal());
    }


    /**
     * 构造查询条件
     *
     * @param req
     * @return LambdaQueryWrapper<PlanDevelopment> 查询条件
     */
    private LambdaQueryWrapper<PersonnelCertificate> buildQuery(PersonnelCertificateReq req) {
        LambdaQueryWrapper<PersonnelCertificate> lqw = new LambdaQueryWrapper<PersonnelCertificate>()
                .like(StrUtil.isNotBlank(req.getEmployeeId()), PersonnelCertificate::getEmployeeId, req.getEmployeeId())
                .like(StrUtil.isNotBlank(req.getHolderName()), PersonnelCertificate::getHolderName, req.getHolderName())
                .eq(StrUtil.isNotBlank(req.getIdNumber()), PersonnelCertificate::getIdNumber, req.getIdNumber())
                // .eq(StrUtil.isNotBlank(req.getMineCode()), PersonnelCertificate::getMineCode, req.getMineCode())
                .eq(StrUtil.isNotBlank(req.getType()), PersonnelCertificate::getType, req.getType())
                .eq(StrUtil.isNotBlank(req.getCertificateStatus()), PersonnelCertificate::getCertificateStatus, req.getCertificateStatus())
                .eq(StrUtil.isNotBlank(req.getWorkUnit()), PersonnelCertificate::getWorkUnit, req.getWorkUnit());
        //.eq(PersonnelCertificate::getDelFlag, "0");
        //.eq(StrUtil.isNotBlank(req.getTypeCoal()), PersonnelCertificate::getTypeCoal, req.getTypeCoal())
        //.eq(StrUtil.isNotBlank(req.getStatus()), PersonnelCertificate::getStatus, req.getStatus());
        return lqw;
    }

    /**
     * @param planSale 查询掘进计划列表
     */
    @Override
    public List<PersonnelCertificateVo> selectList(PersonnelCertificateReq planSale) {
        List<PersonnelCertificate> list = personnelCertificateMapper.selectList(buildQuery(planSale));
        return list.stream().map(p -> {
            PersonnelCertificateVo personnelCertificateVo = new PersonnelCertificateVo();
            BeanUtils.copyProperties(p, personnelCertificateVo);
            return personnelCertificateVo;
        }).collect(Collectors.toList());
    }

    /**
     * @param planSale 新增回采计划
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insert(PersonnelCertificateReq planSale) {
        //自动生成 计划名称 计划编号
        PersonnelCertificate insertObj = new PersonnelCertificate();
        //copyProperties(planSale, insertObj, planSale.getPlanType());
        BeanUtils.copyProperties(planSale, insertObj);
        LambdaQueryWrapper<PersonnelCertificate> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PersonnelCertificate::getEmployeeId, insertObj.getEmployeeId()).eq(PersonnelCertificate::getType, insertObj.getType()).eq(StrUtil.isNotBlank(insertObj.getWorkUnit()), PersonnelCertificate::getWorkUnit, insertObj.getWorkUnit());
        if (this.count(queryWrapper) > 0) {
            throw new HuaNengException(Constants.FAIL, "您要保存的的数据已存在");
        }
        boolean save = this.save(insertObj);
        if (!save) {
            throw new HuaNengException(Constants.FAIL, "您要保存的的数据已存在");
        }
        return true;
    }

    /**
     * @param idList 批量删除
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(List<String> idList) {
        personnelCertificateMapper.deleteBatchIds(idList);
    }

    /**
     * @param planSale 单个修改 按照主键修改信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateById(PersonnelCertificateReq planSale) {
        if (StrUtil.isBlank(planSale.getId())) {
            throw new HuaNengException(Constants.FAIL, "id不能为空");
        }
        PersonnelCertificate updateObj = new PersonnelCertificate();
        BeanUtils.copyProperties(planSale, updateObj);
        ;

        QueryWrapper<PersonnelCertificate> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(StrUtil.isNotBlank(updateObj.getWorkUnit()), "work_unit", updateObj.getWorkUnit());
        queryWrapper.eq("id", updateObj.getId()).eq("type", updateObj.getType());
        Long aLong = personnelCertificateMapper.selectCount(queryWrapper);
        if (aLong > 1) {
            throw new HuaNengException(Constants.FAIL, "已存在同一时段的计划");
        }
        planSale.setUpdateTime(new Date());
        int updateCount = personnelCertificateMapper.updateById(updateObj);
        if (updateCount == 0) {
            throw new HuaNengException(Constants.FAIL, "数据不存在");
        }

    }

    /**
     * @param id 按主键id查询详情
     */
    @Override
    public PersonnelCertificateVo selectDetailById(String id) {
        PersonnelCertificate planSale = personnelCertificateMapper.selectById(id);
        if (planSale == null) {
            throw new HuaNengException(Constants.FAIL, "数据不存在");
        }
        PersonnelCertificateVo personnelCertificateVo = new PersonnelCertificateVo();
        BeanUtils.copyProperties(planSale, personnelCertificateVo);
        return personnelCertificateVo;
    }

}
